/*
 * Copyright 2006-2023 ahtelit.com, All Rights Reserved.
 */

package com.telit.firecommand.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.telit.common.constant.Constant;
import com.telit.common.entity.PageData;
import com.telit.common.exception.ForestBaseException;
import com.telit.common.util.RedisUtils;
import com.telit.common.util.SpringContextHolder;
import com.telit.common.util.WebUtils;
import com.telit.firecommand.config.mqtt.MqttClientManager;
import com.telit.firecommand.config.properties.IotProperties;
import com.telit.firecommand.constant.RedisKeyConstant;
import com.telit.firecommand.model.iot.IotDeviceListModel;
import com.telit.firecommand.model.iot.IotDeviceMeteorologyModel;
import com.telit.firecommand.model.iot.QryDevicesListRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.Validate;

import java.util.*;


/**
 * 升哲物联网设备工具类
 *
 * @author yuezhuang
 * @since 2023-04-27
 */
@Slf4j
public class IotUtil {

    private static MqttClientManager mqttClientManager;

    private static String API_URL = "https://lins-api.sensoro.com";
    public static String MQTT_URL = "wss://lins-api.sensoro.com:443/mqtt";
    private static String APP_ID = "aieeeb582426";
    private static String APP_SECRET = "05fc4d22dcad52ce6556aec29544ec8d1abbe588";
    private static String PROJECT_ID = "1651466636049428482";
    private static String TENANT_ID = "1495725282325143553";
    private static String NONCE = UUID.randomUUID().toString();

    public static final String AICITY = "aicity";
    public static final String LOGIN_URI = "/auth/v2/session/developer/login";
    public static final String DEVICES_LIST_URI = "/device/v1/deviceCenter/devices";
    public static final String METEOROLOGY_URI = "/meteorology/v1/meteorology/";

    private static final Map<String, String> HEADERS = new HashMap<>();

    static {
        HEADERS.put("Content-Type", "application/json");
    }

    /**
     * 初始化配置信息
     *
     * @param iotProperties 配置信息
     */
    public static void init(IotProperties iotProperties) {
        API_URL = iotProperties.getApiUrl();
        MQTT_URL = iotProperties.getMqttUrl();
        APP_ID = iotProperties.getAppId();
        APP_SECRET = iotProperties.getAppSecret();
    }

    public static MqttClientManager obtainMqttClientManager() {
        if (mqttClientManager == null) {
            mqttClientManager = SpringContextHolder.getBean(MqttClientManager.class);
        }
        return mqttClientManager;
    }

    /**
     * 获取mqtt username
     */
    public static String getUsername() {
        return "@northbound:" + IotUtil.APP_ID;
    }

    /**
     * 获取mqtt clientId
     */
    public static String getClientId() {
        return "@northbound:" + IotUtil.PROJECT_ID + "/" + IotUtil.APP_ID + "/" + IotUtil.NONCE;
    }

    /**
     * 获取mqtt password
     */
    public static String getPassword() {
        return IotUtil.getToken();
    }

    /**
     * 获取mqtt 订阅的主题
     */
    public static List<String> getTopicList() {
        return Arrays.asList("northbound/project/" + IotUtil.PROJECT_ID + "/data",
                "northbound/project/" + IotUtil.PROJECT_ID + "/event");
    }

    /**
     * 获取 token
     *
     * @return token
     */
    @SuppressWarnings("unchecked")
    public static String getToken() {
        String token = RedisUtils.get(RedisKeyConstant.IOT_ACCESS_TOKEN);
        if (StrUtil.isNotEmpty(token)) {
            return token;
        }

        Map<String, Object> dataMap = login();
        token = MapUtil.getStr(dataMap, "token");
        String project = MapUtil.getStr(dataMap, "project");
        Map<String, Object> projectData = JSON.parseObject(project, Map.class);
        String tenant = MapUtil.getStr(dataMap, "tenant");
        Map<String, Object> tenantData = JSON.parseObject(tenant, Map.class);
        PROJECT_ID = MapUtil.getStr(projectData, "id");
        TENANT_ID = MapUtil.getStr(tenantData, "id");
        RedisUtils.set(RedisKeyConstant.IOT_ACCESS_TOKEN, token,
                RedisKeyConstant.IOT_ACCESS_TOKEN_EXPIRE_TIME);

        //token发生变化后，重新创建 MqttClient 客户端
//        resetMqttClient();

        return token;
    }

    /**
     * 重新创建 MqttClient 客户端
     */
    public static void resetMqttClient() {
        //删除MQTT客户端
        MqttClientManager.removeMqttClientById(getClientId());

        //断开连接
        MqttClientManager.disConnect(getClientId());

        //重置NONCE
        IotUtil.NONCE = UUID.randomUUID().toString();

        //创建mqtt客户端
        obtainMqttClientManager().createMqttClient(IotUtil.MQTT_URL, IotUtil.getClientId(), IotUtil.getTopicList(),
                IotUtil.getUsername(), IotUtil.getPassword());
    }

    /**
     * 签名
     */
    private static String generateSignature(Long nonce) {
        String text = APP_ID + nonce + AICITY;
        return HmacSHA256Util.hmacSHA256(text, APP_SECRET);
    }

    /**
     * 登录
     */
    private static Map<String, Object> login() {
        Long nonce = System.currentTimeMillis();
        Map<String, Object> requestParams = new HashMap<>();
        requestParams.put("appId", APP_ID);
        requestParams.put("nonce", String.valueOf(nonce));
        requestParams.put("signature", generateSignature(nonce));
        return callRequest(LOGIN_URI, null, Constant.REQUEST_METHOD_POST, null, requestParams);
    }

    /**
     * 气象站详情
     */
    public static IotDeviceMeteorologyModel meteorology(String sn) {
        Map<String, Object> dataMap = callRequest(METEOROLOGY_URI + sn, getToken(), Constant.REQUEST_METHOD_GET, null,
                null);
        return JSON.parseObject(JSON.toJSONString(dataMap), IotDeviceMeteorologyModel.class);
    }

    /**
     * 设备列表
     */
    public static PageData<List<IotDeviceListModel>> devices(QryDevicesListRequest qryDevicesListRequest) {
        Map<String, String> requestParams = new HashMap<>();
        if (qryDevicesListRequest.getPage() != null) {
            requestParams.put("page", qryDevicesListRequest.getPage().toString());
        }
        if (qryDevicesListRequest.getSize() != null) {
            requestParams.put("size", qryDevicesListRequest.getSize().toString());
        }
        if (StrUtil.isNotEmpty(qryDevicesListRequest.getCategories())) {
            requestParams.put("categories",
                    JSON.toJSONString(Arrays.asList(qryDevicesListRequest.getCategories().split(","))));
        }
        if (StrUtil.isNotEmpty(qryDevicesListRequest.getAppUsed())) {
            requestParams.put("appUsed",
                    JSON.toJSONString(Arrays.asList(qryDevicesListRequest.getAppUsed().split(","))));
        }
        if (StrUtil.isNotEmpty(qryDevicesListRequest.getSearch())) {
            requestParams.put("search", qryDevicesListRequest.getSearch());
        }
        if (qryDevicesListRequest.getStartTime() != null) {
            requestParams.put("startTime", String.valueOf(DateUtil.millisecond(qryDevicesListRequest.getStartTime())));
        }
        if (qryDevicesListRequest.getEndTime() != null) {
            requestParams.put("endTime", String.valueOf(DateUtil.millisecond(qryDevicesListRequest.getEndTime())));
        }
//        if (StrUtil.isNotEmpty(qryDevicesListRequest.getProductTypeCode())) {
//
//        }
        //气象站设备
        requestParams.put("productTypeCode", "WS");

        Map<String, Object> dataMap = callRequest(DEVICES_LIST_URI, getToken(), Constant.REQUEST_METHOD_GET,
                requestParams, null);
        List<IotDeviceListModel> values = JSON.parseArray(MapUtil.getStr(dataMap, "list"), IotDeviceListModel.class);
        int total = MapUtil.getInt(dataMap, "total");
        int page = MapUtil.getInt(dataMap, "page");
        int size = MapUtil.getInt(dataMap, "size");
        return PageData.<List<IotDeviceListModel>>builder()
                .count(total)
                .current(page)
                .size(size)
                .datas(values)
                .build();
    }

    /**
     * http请求
     *
     * @param url               请求地址
     * @param getRequestParams  get请求参数
     * @param postRequestParams post请求参数
     *
     * @return http请求结果
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> callRequest(String url, String token, String method,
                                                  Map<String, String> getRequestParams,
                                                  Map<String, Object> postRequestParams) {
        try {
            if (StrUtil.isNotEmpty(token)) {
                HEADERS.put("Authorization", "Bearer " + token);
                HEADERS.put("authorization", "Bearer " + token);
                HEADERS.put("x-lins-projectid", PROJECT_ID);
            }

            String result = null;
            if (Constant.REQUEST_METHOD_GET.equals(method)) {
                log.info("升哲IOT系统，接口地址：{}， 请求参数：{}", API_URL + url, JSON.toJSONString(getRequestParams));

                result = WebUtils.doGetWithRequestParameters(API_URL + url, HEADERS, getRequestParams);
            } else if (Constant.REQUEST_METHOD_POST.equals(method)) {
                log.info("升哲IOT系统，接口地址：{}， 请求参数：{}", API_URL + url, JSON.toJSONString(postRequestParams));

                result = WebUtils.doPostWithRequestBody(true, API_URL + url, JSON.toJSONString(postRequestParams),
                        HEADERS, 0, 0);
            }
            log.info("升哲IOT系统，返回结果：{}", result);

            Map<String, Object> resultMap = JSON.parseObject(result, Map.class);
            Validate.isTrue(MapUtil.getInt(resultMap, "code") == 0);
            String data = MapUtil.getStr(resultMap, "data");
            return JSON.parseObject(data, Map.class);
        } catch (Exception e) {
            log.error("升哲IOT系统，调用失败：{}", e.getMessage());

            throw new ForestBaseException("升哲IOT系统，调用失败：" + e.getMessage());
        }
    }

    public static void main(String[] args) {
//        login();
        QryDevicesListRequest qryDevicesListRequest = new QryDevicesListRequest();
        qryDevicesListRequest.setPage(1);
        qryDevicesListRequest.setSize(10);
        devices(qryDevicesListRequest);
    }

}
